package day28.homework;

/**
 * 包子师傅类，负责制作包子
 * 实现Runnable接口，作为线程任务执行
 * 
 * HashMap：哈希表实现，无序
 * LinkedHashMap：保持插入顺序
 * TreeMap：按键的自然顺序或自定义顺序排序
 * 
 * 这个类代表包子铺的师傅，持续制作包子
 * 使用一个标志位running控制线程的执行
 * 
 * 多线程相关知识点：
 * 1. Runnable接口：实现多线程的一种方式，相比继承Thread类更灵活
 * 2. 线程控制：通过boolean标志位控制线程的执行和停止
 * 3. 线程休眠：使用Thread.sleep()方法模拟实际操作的时间消耗
 * 4. 线程中断处理：正确处理InterruptedException异常
 * 5. 随机数生成：使用Math.random()方法生成随机数，模拟不确定的操作
 */
public class BunChef implements Runnable {
    /** 
     * 包子铺引用，用于调用制作包子的方法
     * 通过构造方法传入，实现对象间的依赖关系
     */
    private BunShop bunShop;
    
    /** 
     * 线程运行标志位，控制线程是否继续执行
     * volatile关键字确保多线程环境下的可见性
     * 当一个线程修改了volatile变量的值，其他线程能立即看到修改后的值
     */
    private volatile boolean running = true;
    
    /**
     * 构造方法，初始化包子师傅
     * 通过构造方法注入依赖，符合面向对象设计原则
     * 
     * @param bunShop 包子铺对象引用
     */
    public BunChef(BunShop bunShop) {
        this.bunShop = bunShop;
    }
    
    /**
     * 线程执行方法，实现包子师傅的制作逻辑
     * 循环制作包子，直到running标志位被设置为false
     * 使用Math.random()随机选择包子口味
     * 使用Thread.sleep()模拟制作包子的时间间隔
     * 
     * 线程执行流程详解：
     * 1. 线程启动后进入run方法开始执行
     * 2. 检查running标志位，如果为true则继续执行
     * 3. 随机选择包子口味（肉馅或蔬菜馅）
     * 4. 调用包子铺的makeBun方法制作包子
     *    - 如果对应口味的包子容器已满，线程会等待
     *    - 制作完成后会唤醒等待的线程
     * 5. 线程休眠一段时间，模拟制作包子的时间消耗
     * 6. 重复步骤2-5，直到running标志位被设置为false
     * 7. 线程正常结束或被中断时退出run方法
     */
    @Override
    public void run() {
        System.out.println("包子师傅: 开始制作包子...");
        
        try {
            // 当running标志位为true时，持续制作包子
            // volatile变量保证了多线程环境下的可见性
            // 当其他线程修改running变量的值时，当前线程能立即看到修改后的值
            while (running) {
                // 随机制作一种口味的包子
                // Math.random()返回0.0到1.0之间的随机数
                // 大于0.5时选择肉馅，否则选择蔬菜馅
                Bun.Flavor flavor = Math.random() > 0.5 ? Bun.Flavor.MEAT : Bun.Flavor.VEGETABLE;
                
                // 制作包子，调用包子铺的makeBun方法
                // 这个方法内部使用了同步机制保证线程安全
                // 如果对应口味的包子容器已满，当前线程会等待
                bunShop.makeBun(flavor);
                
                // 控制制作速度，模拟制作包子需要时间
                // Math.random() * 1000生成0到1000之间的随机数
                // 加上500确保至少休眠500毫秒，最多休眠1500毫秒
                // Thread.sleep()方法使当前线程暂停执行指定时间
                Thread.sleep((long) (Math.random() * 1000) + 500);
            }
        } catch (InterruptedException e) {
            // 当线程在sleep或wait期间被中断时，会抛出InterruptedException异常
            // 这种情况可能发生在调用stop()方法时，主线程中断了包子师傅线程
            System.out.println("包子师傅: 工作被中断");
            // 重新设置线程的中断状态，保持线程的中断状态不变
            // 这是一种良好的编程实践，确保中断状态能正确传递
            Thread.currentThread().interrupt();
        }
        
        System.out.println("包子师傅: 结束制作包子");
    }
    
    /**
     * 停止方法，设置running标志位为false，使线程退出循环
     * 这是一个线程安全的方法，因为只在主线程中调用
     * 
     * 线程控制机制详解：
     * 1. 标志位控制：通过boolean变量running控制线程的执行
     * 2. 可见性保证：使用volatile关键字确保多线程环境下的可见性
     * 3. 优雅停止：不强制终止线程，而是通过标志位让线程自然结束
     * 4. 安全性：该方法只在主线程中调用，不存在多线程竞争问题
     */
    public void stop() {
        // 设置运行标志位为false，使run方法中的while循环退出
        // 由于running变量使用了volatile关键字，修改后的值对包子师傅线程立即可见
        running = false;
    }
}